﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml;
using System.Diagnostics;
using System.ComponentModel;

using System.Text.RegularExpressions;
using Xceed.Wpf.Toolkit;
using Xceed.Wpf.Toolkit.PropertyGrid;
using Xceed.Wpf.Toolkit.PropertyGrid.Editors;
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;

using CustomizedParamList = System.Collections.Generic.Dictionary<string, string>;

namespace dmm
{
    public class ProfileParamOption
    {
        public string Disp { get; set; }
        public string Val { get; set; }

        public ProfileParamOption(string disp, string val)
        {
            Disp = disp;
            Val = val;
        }
    }

    class ProfileParamEditor : ComboBoxEditor
    {
        protected override System.Collections.Generic.IList<object> CreateItemsSource(PropertyItem item)
        {
            Profile p = item.PropertyGrid.SelectedObject as Profile;
            ProfileParam param = p.get_param_def(item.PropertyDescriptor.Name);
            return param.options.ConvertAll<object>(it=>it as object);           
        }
        protected override void SetValueDependencyProperty()
        {
            ValueProperty = System.Windows.Controls.ComboBox.SelectedValueProperty;
        }
        protected override void SetControlProperties()
        {
            Editor.DisplayMemberPath = "Disp";
            Editor.SelectedValuePath = "Val";
        }
    }



    public partial class ProfileManager : UserControl
    {

        Dictionary<string,Profile> profiles = new Dictionary<string,Profile>();
        private Profile current_profile = null;
       

        public Profile SelectedProfile
        {
            get { return current_profile; }
        }


        public ProfileManager()
        {
            InitializeComponent();
        }

        private void onLoaded(object sender, RoutedEventArgs e)
        {
            profile_popup.PlacementTarget = expander1;
            profile_popup2.PlacementTarget = expander2;
        }

        private void onExpanded(object sender, RoutedEventArgs e)
        {
            profile_popup.IsOpen = true;
            //profile_tree
        }

        private void onCollapsed(object sender, RoutedEventArgs e)
        {
            profile_popup.IsOpen = false;
        }

        private void onExpanded2(object sender, RoutedEventArgs e)
        {

            profile_popup2.IsOpen = true;
            //profile_tree
            
            prop_grid.AutoGenerateProperties = true;
            prop_grid.SelectedObject = current_profile;

            foreach (PropertyItem item in prop_grid.Properties)
            {
                ProfileParamEditor editor = new ProfileParamEditor();
                item.Editor = editor.ResolveEditor(item);
               
                ProfileParam param = current_profile.get_param_def(item.PropertyDescriptor.Name);
                if (param.editable)
                {
                    ComboBox box = (item.Editor as ComboBox);
                    box.IsEditable = true;
                }
            }
          
        }

        private void onCollapsed2(object sender, RoutedEventArgs e)
        {
            if (e.Source ==  expander2)
            {
                profile_popup2.IsOpen = false;
            }
        }

        private void profile_tree_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
          
            XmlElement element = (XmlElement)profile_tree.SelectedItem;

            if (element.Name == "group")
            {
                TreeViewItem item = profile_tree.ItemContainerGenerator.ContainerFromItem(element) as TreeViewItem;
                item.IsExpanded = !item.IsExpanded;
            }
            if(element.Name == "profile"){
                string profile_name = element.GetAttribute("name");
                
                if (!profiles.Keys.Contains(profile_name))
                {
                    load_profile(profile_name);
                }
                current_profile = profiles[profile_name];
                prop_grid.SelectedObject = current_profile;
                tbProfile.Text = current_profile.Name;


                /*ProfileParam p = current_profile.get_param_def("vdimension");
                if (p != null)
                {
                    dimension_ctrl.IsEnabled = true;
                    dimension_ctrl.ItemsSource = p.options;
                    dimension_ctrl.SelectedIndex = 0;
                }
                else
                    dimension_ctrl.IsEnabled = false;

                p = current_profile.get_param_def("vzoom");
                if (p != null)
                {
                    zoom_ctrl.IsEnabled = true;
                    zoom_ctrl.ItemsSource = p.options;
                    zoom_ctrl.SelectedIndex = 0;
                }
                else
                    zoom_ctrl.IsEnabled = false;*/

                expander1.IsExpanded = false;
            }
        }

        public Profile get_profile(string profile_name)
        {
            Profile p = null;

            if (profile_name == "")
            {
                System.Windows.MessageBox.Show("please select a ouput video profile first");
                return null;
            }

            profiles.TryGetValue(profile_name, out p);
            return p;
            
        }

        private void load_profile(string profile_name)
        {
            try
            {
                Profile profile = new Profile();
                profile.name = profile_name;

                string path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

                //Uri uri= new Uri(@"pack://siteoforigin:,,,/xml/" + profile_name + @".xml", UriKind.RelativeOrAbsolute);
                string xml = path+"/xml/" + profile_name + @".xml";
                using (XmlReader reader = XmlReader.Create(xml))
                {
                    //PARAM_CATEGORY cat=0;
                    string cat = "";
                    ProfileParam param=null;

                    int level = 0;

                    //level 1: profile
                    //level 2: cat
                    //level 3: param;
                    //level 4:values


                    while (reader.Read())
                    {
                        switch (reader.NodeType)
                        {
                            case XmlNodeType.Element: // The node is an element.
                                level++;

                                if (level == 1)
                                {
                                     int cnt = reader.AttributeCount;
                                     for (int i = 0; i < cnt; i++)
                                     {
                                         reader.MoveToAttribute(i);
                                         if (reader.Name == "ext")
                                         {
                                              if(reader.ReadAttributeValue())
                                              {
                                                profile.FileExt = reader.Value;
                                              }
                                         }
                                     }

                                }
                                if (level == 2)

                                {
                                    cat = reader.Name;
                                    /*if (reader.Name == "general")
                                    {
                                        cat = PARAM_CATEGORY.PARAM_GENERAL_CATEGORY;
                                    }
                                    else if (reader.Name == "video")
                                    {
                                        cat = PARAM_CATEGORY.PARAM_VIDEO_CATEGORY;
                                    }
                                    else if (reader.Name == "audio")
                                    {
                                        cat = PARAM_CATEGORY.PARAM_AUDIO_CATEGORY;
                                    }
                                    else if (reader.Name == "command")
                                    {
                                        cat = PARAM_CATEGORY.PARAM_COMMAND_CATEGORY;

                                    }*/
                                }


                                if(level == 3)
                                {

                                    if (reader.IsEmptyElement) level--;

                                    param = new ProfileParam();
                                    param.cat = cat;
                                    param.Name = reader.Name;

                                    int cnt = reader.AttributeCount;
                                    for(int i=0;i<cnt;i++){
                                        reader.MoveToAttribute(i);

                                        if(reader.Name == "display")
                                        {
                                            if(reader.ReadAttributeValue()){
                                                param.display = reader.Value;
                                            }

                                        }else if(reader.Name == "type")
                                        {
                                        }else if(reader.Name == "value")
                                        {
                                            if(reader.ReadAttributeValue()){
                                                //actually ,this is display in XML
                                                param.default_value = reader.Value;
                                            }
                                        }
                                        else if(reader.Name == "desc")
                                        {
                                            if(reader.ReadAttributeValue()){
                                                param.desc = reader.Value;
                                            }
                                        }else if(reader.Name == "editable")
                                        {
                                            if (reader.ReadAttributeValue())
                                            {
                                                param.editable = (reader.Value == "1");
                                            }
                                        }else{
                                            Debug.Write("Unprocessed attribute :"+reader.Name+"\n");
                                        }
                                    }
                                }

                                if(level == 4)
                                {

                                    if (reader.IsEmptyElement) level--;

                                    Debug.Assert(reader.Name == "list");
                                    int cnt = reader.AttributeCount;
                                    string val = null;
                                    string display = null;
                                    for(int i=0;i<cnt;i++)
                                    {
                                        reader.MoveToAttribute(i);
                                        if(reader.Name == "value")
                                        {
                                             if(reader.ReadAttributeValue())
                                             {
                                                 val = reader.Value;
                                             }

                                        }
                                        else if(reader.Name == "display")
                                        {
                                            if (reader.ReadAttributeValue())
                                            {
                                                display = reader.Value;
                                            }
                                        }

                                      
                                    }
                                    Debug.Assert(val != null);
                                    if (display == null) display = val;
                                   
                                    param.options.Add(new ProfileParamOption(display, val));

                                    if (param.default_value == display)
                                    {
                                        param.default_value = val;
                                    }

                                }


                                break;
                            case XmlNodeType.Text: //Display the text in each element.
                               // if (cat == PARAM_CATEGORY.PARAM_COMMAND_CATEGORY)
                                if(cat=="command")
                                {
                                    profile.cmd = reader.Value;
                                }
                                break;
                            case XmlNodeType.EndElement: //Display the end of the element.
                                if (level == 3)
                                {
                                    if (cat != "general")
                                    profile.add_param(param.Name,param);
                                    param = null;
                                }
                                level--;
                                break;
                        }
                    }

                }

              
                profiles.Add(profile_name,profile);
            }
            catch (Exception e)
            {
                Debug.Write(e);
            }
        }


        /*private NVPairList get_default_setting(string profile_name)
        {
        }*/
    }

    public enum PARAM_CATEGORY
    {
        PARAM_GENERAL_CATEGORY,
        PARAM_VIDEO_CATEGORY,
        PARAM_AUDIO_CATEGORY,
        PARAM_COMMAND_CATEGORY,
    };


    public class ProfileParam
    {
        public string cat;
        private string name;
        public string display;
        public string default_value;
        public string desc;
        public bool editable = false;
       
        public List<ProfileParamOption> options = new List<ProfileParamOption>();


        public string Name{
            get 
            {
                return name;
            }
            set{
                name = value;
            }
        }
    }



    public class Profile : ICustomTypeDescriptor
    {
        public string name;
        public string cmd;
        public string ext;
        public CustomizedParamList user_param = new CustomizedParamList();


        [Category("Standard")]
        public string Name
        {
            get { return name; }
        }

        [Category("Standard")]
        public string FileExt
        {
            get { return ext; }
            set { ext = value; }
        }

        public Dictionary<string, ProfileParam> param_dict = new Dictionary<string, ProfileParam>();

        public void add_param(string name,ProfileParam param)
        {
            param_dict.Add(name,param);
        }


        public ProfileParam get_param_def(string name)
        {
            ProfileParam param= null;
            param_dict.TryGetValue(name, out param);
            return param;

        }

        //instantiate a command for a video with default value


        public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            var props = new PropertyDescriptor[param_dict.Count];
            int i = 0;
            foreach (var prop in param_dict)
            {
                props[i++] = new ProfileParamDescriptor(prop.Key, prop.Value, user_param);
            }
            return new PropertyDescriptorCollection(props);
        }



        #region Boilerplate

        #region Never called
        public string GetComponentName()
        {
            return TypeDescriptor.GetComponentName(this, true);
        }
        public EventDescriptor GetDefaultEvent()
        {
            return TypeDescriptor.GetDefaultEvent(this, true);
        }
        EventDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetEvents()
        {
            return TypeDescriptor.GetEvents(this, true);
        }
        PropertyDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetProperties()
        {
            return GetProperties(null);
        }
        #endregion

        public string GetClassName()
        {
            return TypeDescriptor.GetClassName(this, true);
        }
        public EventDescriptorCollection GetEvents(Attribute[] attributes)
        {
            return TypeDescriptor.GetEvents(this, attributes, true);
        }
        public TypeConverter GetConverter()
        {
            return TypeDescriptor.GetConverter(this, true);
        }
        public object GetPropertyOwner(PropertyDescriptor pd)
        {
            return param_dict;
        }
        public AttributeCollection GetAttributes()
        {
            return TypeDescriptor.GetAttributes(this, true);
        }
        public object GetEditor(Type editorBaseType)
        {
            return TypeDescriptor.GetEditor(this, editorBaseType, true);
        }
        public PropertyDescriptor GetDefaultProperty()
        {
            return null;
        }

        #endregion

        class ProfileParamDescriptor : PropertyDescriptor
        {
            string name;
            ProfileParam param;
            CustomizedParamList custom_param;

            internal ProfileParamDescriptor(string name, ProfileParam param, CustomizedParamList custom_param)
                : base(name, null)
            {
                this.name = name;
                this.param = param;
                this.custom_param = custom_param;
            }
            public override string DisplayName
            {
                get
                {
                    return param.display;
                }
            }
            public override string Description
            {
                get { return param.desc; }
            }
            public override string Category
            {
                get { return param.cat; }
            }
            public override Type PropertyType
            {
                get { return typeof(string); }
            }
            public override void SetValue(object component, object value)
            {
                custom_param[name] = (value as string);
            }
            public override object GetValue(object component)
            {
                string res = "";
                if (custom_param.TryGetValue(name, out res)) 
                {
                }else
                    res = param.default_value;
  
                return res;
            }
            public override bool IsReadOnly
            {
                get { return false; }
            }
            public override Type ComponentType
            {
                get { return null; }
            }
            public override bool CanResetValue(object component)
            {
                return param.default_value != "";
            }
            public override void ResetValue(object component)
            {
                SetValue(name, param.default_value);
            }
            public override bool ShouldSerializeValue(object component)
            {
                return false;
            }
        }

    }
}
